using System;   
using System.IO;

namespace CGMSharp
{
	/// <summary>
	/// Summary description for BinaryUtil.
	/// </summary>
	public class BinaryUtil
	{
		public BinaryUtil()
		{
			
		}

		public static int ReadWord(Stream s)
		{
			return (int)((s.ReadByte() << 8) | s.ReadByte());
		} 

		public static void WriteWord(Stream s, int val)
		{
			s.WriteByte((byte)(val >> 8 & 0xff));
			s.WriteByte((byte)(val & 0xff));
		}

        public static int SignBit(long rawInt, int precision)
        {
            return ((rawInt >> (precision - 1) == 1) ? -1 : 1);
        }

        #region CGM Primitive Data Types

		public static int ReadSI(Stream s, int precision)
		{
            long rawData;
            int SI;
            
            switch (precision)
            {
                case 8:
                    rawData=s.ReadByte();
                    SI = (int)(rawData & 0x7f); 
                    break;
                case 16:
                    rawData = ReadWord(s);
                    SI = (int)(rawData & 0x7fff);
                    break;
                case 24:
                    rawData = (ReadWord(s) << 8) | s.ReadByte();
                    SI = (int)(rawData & 0x7fffff);
                    break;
                case 32:
                    rawData = (ReadWord(s) << 16) | ReadWord(s);
                    SI = (int)(rawData & 0x7fffffff);
                    break;
                default:
                    rawData = 0;
                    SI = 0;
                    break;
            }

            return SI * SignBit(rawData,precision);

		}

		public static void WriteSI(Stream s, int precision, int val)
		{
            
		}

		public static int ReadUI(Stream s, int precision)
		{
            int UI;

            switch (precision)
            {
                case 8:
                    UI = s.ReadByte();
                    break;
                case 16:
                    UI = ReadWord(s);
                    break;
                case 24:
                    UI = (ReadWord(s) << 8) | s.ReadByte();
                    break;
                case 32:
                    UI = (ReadWord(s) << 16) | ReadWord(s);
                    break;
                default:
                    UI = 0;
                    break;
            }

            return UI;
		}

		public static void WriteUI(Stream s, int precision, int val)
		{

		}

		public static double ReadFX(Stream s, int precision)
		{
            int whole, fraction;

            switch (precision)
            {
                case 32:
                    whole = ReadSI(s, 16);
                    fraction = ReadUI(s, 16);
                    break;
                case 64:
                    whole = ReadSI(s, 32);
                    fraction = ReadUI(s, 32);
                    break;
                default:
                    whole = 0;
                    fraction = 0;
                    break;
            }

            return whole+(fraction/(Math.Pow(2,16)));
		}

		public static void WriteFX(Stream s, int precision, double val)
		{
            //switch (precision)
            //{
            //    case 32:

            //        break;
            //    case 64:

            //        break;
            //    default:

            //        break;
            //}
		}

		public static double ReadFP(Stream s, int precision)
		{
            int exponent, sign, word1;
            long fraction;

            switch (precision)
            {
                case 32:
                    word1 = ReadWord(s);
                    sign = word1 >> 15;
                    exponent = (word1 >> 7) & 0xff;
                    fraction = ((word1 & 0x7f) << 16) | ReadWord(s);
                    break;
                case 64:
                    word1 = ReadWord(s);
                    sign = word1 >> 15;
                    exponent = (word1 >> 4) & 0x7ff;
                    fraction = ((word1 & 0xf) << 48) | (ReadWord(s)<<32) | (ReadWord(s)<< 16) | ReadWord(s);
                    break;
                default:
                    exponent = 0;
                    fraction = 0;
                    sign = 0;
                    break;
            }

            if ((exponent == 255 & precision==32) | (exponent ==  2047 & precision==64))
            {
                if (fraction != 0) 
                    return 0;
                return  (int)(sign==0 ? double.MaxValue : double.MinValue);
            }

            if (exponent == 0)
            {
                if (fraction == 0)
                    return 0;
                return ((double)fraction/Math.Pow(10,fraction.ToString().Length)*(Math.Pow(2,precision==32?-126:-1022)));
            }
		
            // There must be a fast way to append a decimal to the front of a number without using string op's
            return (((double)fraction/Math.Pow(10,fraction.ToString().Length)+1)*(Math.Pow(2,precision==32?-127:-1023)));
        }


		public static void WriteFP(Stream s, int precision, double val)
		{

		}

        public static char ReadChar(Stream s, int precision)
        {
            switch (precision)
            {
                case 8:
                    return (char)s.ReadByte();
                case 16:
                    return (char)ReadWord(s);
                default:
                    return (char)s.ReadByte();
            } 
        }

        public static void WriteChar(Stream s, int precision)
        {

        }

		#endregion

	}
}
